Fast acrobatic maneuvers enable arboreal spiders to hunt dangerous prey

Authors:

Alfonso Aceves-Aparicio*1, 2, Ajay Narendra1, Donald James McLean1, Elizabeth C. Lowe1, Marcelo Christian2, Jonas O. Wolff1, Jutta M. Schneider2 and Marie E. Herberstein1

1, Department of Biological Sciences, Macquarie University, Sydney, NSW, 2109, Australia

2, Institute of Zoology, Universität Hamburg, Hamburg, Germany Corresponding author: Alfonso Aceves-Aparicio Correspondence:

This is the code used to extract velocity data and generate figures from the attack sequences recorded as high speed video.

library(trajr)
library(tidyverse)
library(readxl)
library(kableExtra)
library(patchwork)
# library(lessR)

Load excel

Excel files contain control data for each video sequence. And manually scored behaviours occurring during the attack strike phase.

ajay_page1 <- read_excel("./Data/velocity_5seq_20200219a.xlsx", col_names = T, 
sheet = "velocity_5seq_20200219", range = "A1:AB23")%>% 
  rename("filename" = "f-name") %>% 
  mutate(filename = str_replace(filename, ".$", "")) %>% 
  rename("contact" = Seq3...15) %>%
  mutate(firstMoveFrame = frame1 - posFile_start)
# View(ajay_page1)
# current A1:AB23
# alternative range: A1:J23
# ajay_page1 %>% View()

Matching pos files with spreadsheet

# Grab the names of all the files in the working directory as set above

all_pos <- list.files("./Data2", pattern =".pos", full.names = TRUE)

# Grabs the names of the video files from the control spreadsheet
# note the current directory only contains videos from the chronos camera
input_list <- ajay_page1 %>% 
  select("filename") %>% 
  pull()

# input_list

# creates a single object to be used as a pattern to grab the pos files that match those in the spreadsheet
pattern <- paste(input_list, sep="", collapse="|")

# list of pos files that match names in the spreadsheets
chosen_pos <- all_pos[grepl(pattern, all_pos)]

Containers

# first containers --------------------------------------------------------

# coord_files <- chosen_pos %>% 
  # str_subset(pattern = "-(\\d){2}.pos$")

coord_files <- chosen_pos %>% 
  str_subset(pattern = "(\\d|\\d_fail)\\.pos$")

# scale_files <- chosen_pos %>% 
  # str_subset(pattern = "_(\\d){2}mm.pos$")

scale_files <- chosen_pos %>% 
  str_subset(pattern = "(\\d){1,}_scale_(\\d){1,}(mm)|(\\d){1,}_fail_scale_(\\d){1,}(mm)\\.pos$")

# extract the known distances from the scale files
the_scales <- scale_files %>% 
  as.data.frame() %>% 
  rename("scaleFiles" = ".") %>% 
  mutate(scaleValues =  str_extract(scaleFiles, pattern = "_(\\d){1,2}mm")) %>% 
  mutate(scaleValues =  str_extract(string = scaleValues, pattern = "_\\d+")) %>% 
  mutate(scaleValues = str_replace(scaleValues, pattern = "_", replacement = "0.0")) %>% 
  mutate(scaleValues = as.numeric(scaleValues))

Creating trajectory objects

We used the R package “Trajr” to generate the trajectories (the path of the moving spiders) followed by the spiders during the duration of the attack strike against the ant prey.

Each trajectory was smoothed by applying a Savitzky-Golay to reduce high frequency noise while preserving the shape of the trajectory (function: TrajSmoothSG). Further, we used the TrajDerivatives function to calculate change in speed along a each trajectory. The outcome is stored in a “derivatives” object.

Trajr:

McLean DJ, Skowron Volponi MA. trajr: An R package for characterisation of animal trajectories. Ethology. 2018;00:1–9. https://doi.org/10.1111/eth.12739.

https://cran.rstudio.com/web/packages/trajr/vignettes/trajr-vignette.html

derivs_list <- pmap(list(coord_files, scale_files, the_scales$scaleValues), loadSample_FromList2) %>% 
  map(TrajSmoothSG, p = 5, n = 23) %>% 
  map(TrajDerivatives) %>% 
  set_names(mylabelseq("Derivs_", 1, 22, 1))

derivs_names <- names(derivs_list)

Plots for change in speed along a each trajectory

Compact view

par(mfrow = c(3,2));for(i in seq_along(derivs_names)) {
  derivs_list[[i]] %>% plotSpeed()
  title(derivs_names[i])
}

Large view

for(i in seq_along(derivs_names)) {
  derivs_list[[i]] %>% plotSpeed()
  title(derivs_names[i])
}

Excluding trajectory 3

Exploration of the trajectory and speed change of the third high speed video showed an usual pattern. Further revision of the video showed that this was a failed attacked trigger towards an ant at a greater distance. Thus, the ant slayer spider did not attempt to tag the ant prey with silk. For this, the sequence is excluded.

trajs_list <- list(coords = coord_files, scales = scale_files, scaleValues = the_scales)
traj_03 <- loadSample_FromList(listObject = trajs_list, number = 3)

par(mfrow = c(1,2)); derivs_list$Derivs_03 %>% plotSpeed(); plot(traj_03, lwd = 1, lty = 1)

Separating distinct trajectories

The following trajectories do not fit general settings applied to the rest of the trajectories and are thus using particular settings shown below (section “Distinct trajectories”).

removables <- c(2, 3, 12)

derivs_list_short <- derivs_list[- removables]
derivs_names_short <- derivs_names[- removables]
# names(derivs_list_short) <- derivs_names_short

Frame indexes

# The "IndexLimitsManual" function pulls the index position of the following frames:
# last frame where speed is zero (the onset of the ant slayer attack)
# frame where the acrobatic strike reaches its maxumum speed

# default values used for the function
# IndexLimitsManual(derivs_object = derivs_list_sample$Derivs_01, startThreshold = 1e-8, thresholdFrame = 1, limit_range = 155, window_size = 35)

indexes_short <- map(derivs_list_short, IndexLimitsManual)
# names(indexes_short)

Maxima speeds

The following plots show the speed change during the first phase of the attack (acrobatic strike) The blue vertical line marks the onset of the spiders’ attack (the spider begins moving) The red line shows where the peak speed was reached during the acrobatic strike Note this is restricted to the speeds achieved by the spiders while directing its attack to the ant prey and before dropping off from the trunk surface.

pmap(list(derivs_list_short, as.list(names(derivs_list_short)), indexes_short), 
     ~ggplot() + geom_line(aes(x= ..1$speedTimes*1000, y= ..1$speed*100)) +
       ggtitle(..2) +
       geom_vline(xintercept = ..3$`maxim(um/a)`*4, col = "red")+
       geom_vline(xintercept = c(..3$start_index)*4, col = "blue") + 
       xlab("Time (ms)") +
       ylab("Speed (cm/s)") +
       theme_bw()
)
## $Derivs_01

## 
## $Derivs_04

## 
## $Derivs_05

## 
## $Derivs_06

## 
## $Derivs_07

## 
## $Derivs_08

## 
## $Derivs_09

## 
## $Derivs_10

## 
## $Derivs_11

## 
## $Derivs_13

## 
## $Derivs_14

## 
## $Derivs_15

## 
## $Derivs_16

## 
## $Derivs_17

## 
## $Derivs_18

## 
## $Derivs_19

## 
## $Derivs_20

## 
## $Derivs_21

## 
## $Derivs_22

Distinct trajectories

Trajectories 02 and 12 were affected by noisy speed curves before the onset of the attack. These were adjusted and corroborated with visual inspection of the videos to make sure that the selected frame was the last one before the attack onset.

# removables <- c(2, 3, 12)

derivs_list_special <- derivs_list[removables]
derivs_names_special <- derivs_names[removables]
names(derivs_list_special) <- derivs_names_special
# str(derivs_list_special)

Derivs 02

# get index frames
indexes_derivs_02 <- IndexLimitsManual(derivs_object = derivs_list_special$Derivs_02, startThreshold = 1e-8, thresholdFrame = 19, limit_range = 155, window_size = 25)
# plot
ggplot() +
  geom_line(aes(x = derivs_list_special$Derivs_02$speedTimes*1000, y = derivs_list_special$Derivs_02$speed*100)) +
  geom_vline(xintercept = indexes_derivs_02$`maxim(um/a)`[2]*4, col = "red") +
  geom_vline(xintercept = c(indexes_derivs_02$start_index, indexes_derivs_02$end_index)*4, col = "blue") + 
  labs(title = "Derivs_02", 
       x = "Time (ms)",
       y = "Speed (cm/s)") +
  theme_minimal()

# indexes_derivs_02$`maxim(um/a)`
# indexes_derivs_02$end_index

Derivs 12

# get index frames
indexes_derivs_12 <- IndexLimitsManual(derivs_object = derivs_list_special$Derivs_12, startThreshold = 1e-8, thresholdFrame = 19, limit_range = 155, window_size = 35)

# plot
ggplot() +
  geom_line(aes(x = derivs_list_special$Derivs_12$speedTimes*1000, y = derivs_list_special$Derivs_12$speed*100)) +
  geom_vline(xintercept = indexes_derivs_12$`maxim(um/a)`*4, col = "red") +
  geom_vline(xintercept = c(indexes_derivs_12$start_index, indexes_derivs_12$end_index)*4, col = "blue") + 
  labs(title = "Derivs_12", 
       x = "Time (ms)",
       y = "Speed (cm/s)") +
  theme_minimal()

# indexes_derivs_02$`maxim(um/a)`
# indexes_derivs_02$end_index

Figure 1 Panel F

The figure plots the speed change from the last frame before the acrobatic attack onset to the maximum speed reached for 17/19 inspected high speed videos. The remaining 2 (02 and 12) are added later.

# loop me up!
# colour palette
cbp1 <- c("#999999", "#E69F00", "#56B4E9", "#009E73",
          "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
# to recycle colours
cbp1_24 <- rep(cbp1, 3)

mp <- ggplot()
for(i in seq_along(derivs_list_short)) {
  
  idata <- tibble("speed" = derivs_list_short[[i]]$speed[indexes_short[[i]]$start_index:indexes_short[[i]]$`maxim(um/a)`]) %>% 
    mutate("index" = seq_along(speed)-1)
  
  mp <- mp + geom_line(data = idata, 
                       aes(x = index*4, y = speed*100), colour = cbp1_24[i]) +
    geom_point(data = idata,
               aes(x = last(index)*4, 
                   y =  last(speed*100)), 
               colour = cbp1_24[i]) +
    expand_limits(x = c(0, 160), y = c(0, 65)) +
    ylab("Speed (cm/s)") +
    xlab("Time (ms)") +
    theme_classic() +
    theme(panel.border = element_blank())
}

# the version below does not include speed for trajectories 02 and 12
# print(mp)


# mp + 
#   scale_y_continuous(expand = expansion(mult = c(0, .1))) +
#   scale_x_continuous(expand = expansion(mult = c(0, .1)))

Curves for trajectories 02 and 12 are created with the distinct settings created before to capture the correct frames of importance

# 02
derivs_02_data <- tibble("speed" = derivs_list_special$Derivs_02$speed[indexes_derivs_02$start_index:indexes_derivs_02$`maxim(um/a)`[2]]) %>% 
  mutate("index" = seq_along(speed)-1)

mp <- mp  +
geom_line(data = derivs_02_data, 
                     aes(x = index*4, y = speed*100), colour = cbp1_24[7]) +
  geom_point(data = derivs_02_data,
             aes(x = last(index)*4, 
                 y =  last(speed*100)), 
             colour = cbp1_24[7]) +
  expand_limits(x = c(0, 160), y = c(0, 65)) +
  ylab("Speed (cm/s)") +
  xlab("Time (ms)") +
  theme_bw()

# 12
derivs_12_data <- tibble("speed" = derivs_list_special$Derivs_12$speed[indexes_derivs_12$start_index:indexes_derivs_12$`maxim(um/a)`]) %>% 
  mutate("index" = seq_along(speed)-1)

mp <- mp  +
geom_line(data = derivs_12_data, 
                     aes(x = index*4, y = speed*100), colour = cbp1_24[8]) +
  geom_point(data = derivs_12_data,
             aes(x = last(index)*4, 
                 y =  last(speed*100)), 
             colour = cbp1_24[8]) +
  expand_limits(x = c(0, 160), y = c(0, 65)) +
  ylab("Speed (cm/s)") +
  xlab("Time (ms)") +
  theme_bw()

Plot including speed changes for all trajectories

print(mp)

# mp+theme(panel.border = element_blank())

Speed & duration

Max speeds for each spider and the elapsed time while going from 0 to to max.

results <- map_dfr(derivs_list_short, SpeedAndTime2)
# results %>% kbl() %>% 
#   kable_styling(full_width = F)

# rename("Max speed (cm/s)" = max_speed, 
#        "Elapsed time (ms)" = elapsed_time)
res_02 <- SpeedAndTime2(derivatives_list = derivs_list_special$Derivs_02, thresholdFrame = 19, window_size = 25, multiMax = 2)

res_12 <- SpeedAndTime2(derivatives_list = derivs_list_special$Derivs_12, thresholdFrame = 19, window_size = 35)
speeds_times <- bind_rows(results, res_02, res_12) %>% 
  mutate(camefrom = c(derivs_names_short, "Derivs_02", "Derivs_12")) 

speeds_times %>% kbl() %>% 
  kable_styling(full_width = F)
max_speed elapsed_time camefrom
11.57657 116 Derivs_01
29.94638 112 Derivs_04
61.83679 132 Derivs_05
19.86896 128 Derivs_06
11.17088 96 Derivs_07
21.52736 120 Derivs_08
31.64278 104 Derivs_09
33.36874 152 Derivs_10
14.53998 92 Derivs_11
29.30936 100 Derivs_13
29.20735 104 Derivs_14
15.24193 84 Derivs_15
25.19305 108 Derivs_16
33.06568 88 Derivs_17
25.37552 108 Derivs_18
23.51403 104 Derivs_19
30.45109 92 Derivs_20
22.21806 76 Derivs_21
15.98763 108 Derivs_22
24.35238 148 Derivs_02
32.73323 96 Derivs_12
speeds_times %>% 
  summarise(avgSpeed = mean(max_speed), avgTime = mean(elapsed_time))
# the median
table(speeds_times$elapsed_time)
## 
##  76  84  88  92  96 100 104 108 112 116 120 128 132 148 152 
##   1   1   1   2   2   1   3   3   1   1   1   1   1   1   1
median(speeds_times$elapsed_time) 
## [1] 104
inset <- speeds_times %>%
  ggplot() +
  geom_boxplot(aes(elapsed_time)) +
  expand_limits(x = c(0, 160)) +
  theme( panel.grid = element_blank(),
         axis.title = element_blank(),
         axis.text = element_blank(),
         # panel.background = element_blank(),
         panel.background = element_rect(fill = "transparent",colour = NA),
         plot.background = element_rect(fill = "transparent",colour = NA),
)
  
inset <- inset +
  theme(legend.position = "none",
        panel.grid = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        # rect = element_rect(fill = "transparent"),
        # panel.background = element_blank(),
        )

Panel F in figure 1 including inset box plot for elapsed time during speed change

# mp+geom_vline(xintercept = 104)+geom_vline(xintercept = 152) +
# inset_element (p = inset,
# left = -0.018,
# bottom = 0.80,
# right = 1.012,
# top = 0.95, align_to = "panel")

ggp_combi <- mp + theme_classic() + 
  inset_element (p = inset,
                 left = -0.018,
                 bottom = 0.89,
                 right = 1.012,
                 top = 0.99, align_to = "panel")
ggp_combi

# ggsave(filename = "panelF.pdf", plot = ggp_combi, device = "pdf", path = "./gg_plots")
# setwd("/Users/alfonsoaceves/Downloads/Ant Slayer Speed/gg_plots")
# write_csv(speeds_times, "speeds_times.csv")
# title: "R Notebook"
# output:
#   html_document:
#     code_folding: "show"
#     toc: TRUE
#     toc_float: TRUE
#     df_print: paged
# editor_options:
#   chunk_output_type: console


LS0tCnRpdGxlOiAiQW50IFNsYXllciIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93IgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMgRmFzdCBhY3JvYmF0aWMgbWFuZXV2ZXJzIGVuYWJsZSBhcmJvcmVhbCBzcGlkZXJzIHRvIGh1bnQgZGFuZ2Vyb3VzIHByZXkKCioqQXV0aG9yczoqKgoKQWxmb25zbyBBY2V2ZXMtQXBhcmljaW9cKl4xLMKgMl4sIEFqYXkgTmFyZW5kcmFeMV4sIERvbmFsZCBKYW1lcyBNY0xlYW5eMSxeIEVsaXphYmV0aCBDLiBMb3dlXjFeLCBNYXJjZWxvIENocmlzdGlhbl4yXiwgSm9uYXMgTy4gV29sZmZeMV4sIEp1dHRhIE0uIFNjaG5laWRlcl4yXiBhbmQgTWFyaWUgRS4gSGVyYmVyc3RlaW5eMV4KCjEsIERlcGFydG1lbnQgb2YgQmlvbG9naWNhbCBTY2llbmNlcywgTWFjcXVhcmllIFVuaXZlcnNpdHksIFN5ZG5leSwgTlNXLCAyMTA5LCBBdXN0cmFsaWEKCjIsIEluc3RpdHV0ZSBvZiBab29sb2d5LCBVbml2ZXJzaXTDpHQgSGFtYnVyZywgSGFtYnVyZywgR2VybWFueSBDb3JyZXNwb25kaW5nIGF1dGhvcjogQWxmb25zbyBBY2V2ZXMtQXBhcmljaW8gQ29ycmVzcG9uZGVuY2U6IFtiaW9hcmFjaFxAZ21haWwuY29tXShtYWlsdG86YmlvYXJhY2hAZ21haWwuY29tKXsuZW1haWx9CgpUaGlzIGlzIHRoZSBjb2RlIHVzZWQgdG8gZXh0cmFjdCB2ZWxvY2l0eSBkYXRhIGFuZCBnZW5lcmF0ZSBmaWd1cmVzIGZyb20gdGhlIGF0dGFjayBzZXF1ZW5jZXMgcmVjb3JkZWQgYXMgaGlnaCBzcGVlZCB2aWRlby4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodHJhanIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHBhdGNod29yaykKIyBsaWJyYXJ5KGxlc3NSKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmdldHdkKCkKIyBzZXR3ZCgiL1VzZXJzL2FsZm9uc29hY2V2ZXMvRG93bmxvYWRzL0FudCBTbGF5ZXIgU3BlZWQvIikKc291cmNlKCIuL1IvZnVuY3Rpb25zLlIiKQpgYGAKCiMjIExvYWQgZXhjZWwKCkV4Y2VsIGZpbGVzIGNvbnRhaW4gY29udHJvbCBkYXRhIGZvciBlYWNoIHZpZGVvIHNlcXVlbmNlLiBBbmQgbWFudWFsbHkgc2NvcmVkIGJlaGF2aW91cnMgb2NjdXJyaW5nIGR1cmluZyB0aGUgYXR0YWNrIHN0cmlrZSBwaGFzZS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmFqYXlfcGFnZTEgPC0gcmVhZF9leGNlbCgiLi9EYXRhL3ZlbG9jaXR5XzVzZXFfMjAyMDAyMTlhLnhsc3giLCBjb2xfbmFtZXMgPSBULCAKc2hlZXQgPSAidmVsb2NpdHlfNXNlcV8yMDIwMDIxOSIsIHJhbmdlID0gIkExOkFCMjMiKSU+JSAKICByZW5hbWUoImZpbGVuYW1lIiA9ICJmLW5hbWUiKSAlPiUgCiAgbXV0YXRlKGZpbGVuYW1lID0gc3RyX3JlcGxhY2UoZmlsZW5hbWUsICIuJCIsICIiKSkgJT4lIAogIHJlbmFtZSgiY29udGFjdCIgPSBTZXEzLi4uMTUpICU+JQogIG11dGF0ZShmaXJzdE1vdmVGcmFtZSA9IGZyYW1lMSAtIHBvc0ZpbGVfc3RhcnQpCiMgVmlldyhhamF5X3BhZ2UxKQojIGN1cnJlbnQgQTE6QUIyMwojIGFsdGVybmF0aXZlIHJhbmdlOiBBMTpKMjMKIyBhamF5X3BhZ2UxICU+JSBWaWV3KCkKCgpgYGAKCiMjIE1hdGNoaW5nIHBvcyBmaWxlcyB3aXRoIHNwcmVhZHNoZWV0CgpgYGB7cn0KIyBHcmFiIHRoZSBuYW1lcyBvZiBhbGwgdGhlIGZpbGVzIGluIHRoZSB3b3JraW5nIGRpcmVjdG9yeSBhcyBzZXQgYWJvdmUKCmFsbF9wb3MgPC0gbGlzdC5maWxlcygiLi9EYXRhMiIsIHBhdHRlcm4gPSIucG9zIiwgZnVsbC5uYW1lcyA9IFRSVUUpCgojIEdyYWJzIHRoZSBuYW1lcyBvZiB0aGUgdmlkZW8gZmlsZXMgZnJvbSB0aGUgY29udHJvbCBzcHJlYWRzaGVldAojIG5vdGUgdGhlIGN1cnJlbnQgZGlyZWN0b3J5IG9ubHkgY29udGFpbnMgdmlkZW9zIGZyb20gdGhlIGNocm9ub3MgY2FtZXJhCmlucHV0X2xpc3QgPC0gYWpheV9wYWdlMSAlPiUgCiAgc2VsZWN0KCJmaWxlbmFtZSIpICU+JSAKICBwdWxsKCkKCiMgaW5wdXRfbGlzdAoKIyBjcmVhdGVzIGEgc2luZ2xlIG9iamVjdCB0byBiZSB1c2VkIGFzIGEgcGF0dGVybiB0byBncmFiIHRoZSBwb3MgZmlsZXMgdGhhdCBtYXRjaCB0aG9zZSBpbiB0aGUgc3ByZWFkc2hlZXQKcGF0dGVybiA8LSBwYXN0ZShpbnB1dF9saXN0LCBzZXA9IiIsIGNvbGxhcHNlPSJ8IikKCiMgbGlzdCBvZiBwb3MgZmlsZXMgdGhhdCBtYXRjaCBuYW1lcyBpbiB0aGUgc3ByZWFkc2hlZXRzCmNob3Nlbl9wb3MgPC0gYWxsX3Bvc1tncmVwbChwYXR0ZXJuLCBhbGxfcG9zKV0KYGBgCgojIyBDb250YWluZXJzCgpgYGB7cn0KIyBmaXJzdCBjb250YWluZXJzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIGNvb3JkX2ZpbGVzIDwtIGNob3Nlbl9wb3MgJT4lIAogICMgc3RyX3N1YnNldChwYXR0ZXJuID0gIi0oXFxkKXsyfS5wb3MkIikKCmNvb3JkX2ZpbGVzIDwtIGNob3Nlbl9wb3MgJT4lIAogIHN0cl9zdWJzZXQocGF0dGVybiA9ICIoXFxkfFxcZF9mYWlsKVxcLnBvcyQiKQoKIyBzY2FsZV9maWxlcyA8LSBjaG9zZW5fcG9zICU+JSAKICAjIHN0cl9zdWJzZXQocGF0dGVybiA9ICJfKFxcZCl7Mn1tbS5wb3MkIikKCnNjYWxlX2ZpbGVzIDwtIGNob3Nlbl9wb3MgJT4lIAogIHN0cl9zdWJzZXQocGF0dGVybiA9ICIoXFxkKXsxLH1fc2NhbGVfKFxcZCl7MSx9KG1tKXwoXFxkKXsxLH1fZmFpbF9zY2FsZV8oXFxkKXsxLH0obW0pXFwucG9zJCIpCgojIGV4dHJhY3QgdGhlIGtub3duIGRpc3RhbmNlcyBmcm9tIHRoZSBzY2FsZSBmaWxlcwp0aGVfc2NhbGVzIDwtIHNjYWxlX2ZpbGVzICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJlbmFtZSgic2NhbGVGaWxlcyIgPSAiLiIpICU+JSAKICBtdXRhdGUoc2NhbGVWYWx1ZXMgPSAgc3RyX2V4dHJhY3Qoc2NhbGVGaWxlcywgcGF0dGVybiA9ICJfKFxcZCl7MSwyfW1tIikpICU+JSAKICBtdXRhdGUoc2NhbGVWYWx1ZXMgPSAgc3RyX2V4dHJhY3Qoc3RyaW5nID0gc2NhbGVWYWx1ZXMsIHBhdHRlcm4gPSAiX1xcZCsiKSkgJT4lIAogIG11dGF0ZShzY2FsZVZhbHVlcyA9IHN0cl9yZXBsYWNlKHNjYWxlVmFsdWVzLCBwYXR0ZXJuID0gIl8iLCByZXBsYWNlbWVudCA9ICIwLjAiKSkgJT4lIAogIG11dGF0ZShzY2FsZVZhbHVlcyA9IGFzLm51bWVyaWMoc2NhbGVWYWx1ZXMpKQpgYGAKCiMjIENyZWF0aW5nIHRyYWplY3Rvcnkgb2JqZWN0cwoKV2UgdXNlZCB0aGUgUiBwYWNrYWdlICJUcmFqciIgdG8gZ2VuZXJhdGUgdGhlIHRyYWplY3RvcmllcyAodGhlIHBhdGggb2YgdGhlIG1vdmluZyBzcGlkZXJzKSBmb2xsb3dlZCBieSB0aGUgc3BpZGVycyBkdXJpbmcgdGhlIGR1cmF0aW9uIG9mIHRoZSBhdHRhY2sgc3RyaWtlIGFnYWluc3QgdGhlIGFudCBwcmV5LgoKRWFjaCB0cmFqZWN0b3J5IHdhcyBzbW9vdGhlZCBieSBhcHBseWluZyBhIFNhdml0emt5LUdvbGF5IHRvIHJlZHVjZSBoaWdoIGZyZXF1ZW5jeSBub2lzZSB3aGlsZSBwcmVzZXJ2aW5nIHRoZSBzaGFwZSBvZiB0aGUgdHJhamVjdG9yeSAoZnVuY3Rpb246IFRyYWpTbW9vdGhTRykuIEZ1cnRoZXIsIHdlIHVzZWQgdGhlIFRyYWpEZXJpdmF0aXZlcyBmdW5jdGlvbiB0byBjYWxjdWxhdGUgY2hhbmdlIGluIHNwZWVkIGFsb25nIGEgZWFjaCB0cmFqZWN0b3J5LiBUaGUgb3V0Y29tZSBpcyBzdG9yZWQgaW4gYSAiZGVyaXZhdGl2ZXMiIG9iamVjdC4KClRyYWpyOgoKTWNMZWFuIERKLCBTa293cm9uIFZvbHBvbmkgTUEuIHRyYWpyOiBBbiBSIHBhY2thZ2UgZm9yIGNoYXJhY3RlcmlzYXRpb24gb2YgYW5pbWFsIHRyYWplY3Rvcmllcy4gRXRob2xvZ3kuIDIwMTg7MDA6MS0tOS4gPGh0dHBzOi8vZG9pLm9yZy8xMC4xMTExL2V0aC4xMjczOS4+Cgo8aHR0cHM6Ly9jcmFuLnJzdHVkaW8uY29tL3dlYi9wYWNrYWdlcy90cmFqci92aWduZXR0ZXMvdHJhanItdmlnbmV0dGUuaHRtbD4KCmBgYHtyfQpkZXJpdnNfbGlzdCA8LSBwbWFwKGxpc3QoY29vcmRfZmlsZXMsIHNjYWxlX2ZpbGVzLCB0aGVfc2NhbGVzJHNjYWxlVmFsdWVzKSwgbG9hZFNhbXBsZV9Gcm9tTGlzdDIpICU+JSAKICBtYXAoVHJhalNtb290aFNHLCBwID0gNSwgbiA9IDIzKSAlPiUgCiAgbWFwKFRyYWpEZXJpdmF0aXZlcykgJT4lIAogIHNldF9uYW1lcyhteWxhYmVsc2VxKCJEZXJpdnNfIiwgMSwgMjIsIDEpKQoKZGVyaXZzX25hbWVzIDwtIG5hbWVzKGRlcml2c19saXN0KQpgYGAKCiMjIFBsb3RzIGZvciBjaGFuZ2UgaW4gc3BlZWQgYWxvbmcgYSBlYWNoIHRyYWplY3Rvcnkgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgoKIyMjIENvbXBhY3QgdmlldwpgYGB7cn0KcGFyKG1mcm93ID0gYygzLDIpKTtmb3IoaSBpbiBzZXFfYWxvbmcoZGVyaXZzX25hbWVzKSkgewogIGRlcml2c19saXN0W1tpXV0gJT4lIHBsb3RTcGVlZCgpCiAgdGl0bGUoZGVyaXZzX25hbWVzW2ldKQp9CmBgYAoKIyMjIExhcmdlIHZpZXcKCmBgYHtyfQpmb3IoaSBpbiBzZXFfYWxvbmcoZGVyaXZzX25hbWVzKSkgewogIGRlcml2c19saXN0W1tpXV0gJT4lIHBsb3RTcGVlZCgpCiAgdGl0bGUoZGVyaXZzX25hbWVzW2ldKQp9CmBgYAoKCgojIyBFeGNsdWRpbmcgdHJhamVjdG9yeSAzCgpFeHBsb3JhdGlvbiBvZiB0aGUgdHJhamVjdG9yeSBhbmQgc3BlZWQgY2hhbmdlIG9mIHRoZSB0aGlyZCBoaWdoIHNwZWVkIHZpZGVvIHNob3dlZCBhbiB1c3VhbCBwYXR0ZXJuLiBGdXJ0aGVyIHJldmlzaW9uIG9mIHRoZSB2aWRlbyBzaG93ZWQgdGhhdCB0aGlzIHdhcyBhIGZhaWxlZCBhdHRhY2tlZCB0cmlnZ2VyIHRvd2FyZHMgYW4gYW50IGF0IGEgZ3JlYXRlciBkaXN0YW5jZS4gVGh1cywgdGhlIGFudCBzbGF5ZXIgc3BpZGVyIGRpZCBub3QgYXR0ZW1wdCB0byB0YWcgdGhlIGFudCBwcmV5IHdpdGggc2lsay4gRm9yIHRoaXMsIHRoZSBzZXF1ZW5jZSBpcyBleGNsdWRlZC4KCmBgYHtyfQp0cmFqc19saXN0IDwtIGxpc3QoY29vcmRzID0gY29vcmRfZmlsZXMsIHNjYWxlcyA9IHNjYWxlX2ZpbGVzLCBzY2FsZVZhbHVlcyA9IHRoZV9zY2FsZXMpCnRyYWpfMDMgPC0gbG9hZFNhbXBsZV9Gcm9tTGlzdChsaXN0T2JqZWN0ID0gdHJhanNfbGlzdCwgbnVtYmVyID0gMykKCnBhcihtZnJvdyA9IGMoMSwyKSk7IGRlcml2c19saXN0JERlcml2c18wMyAlPiUgcGxvdFNwZWVkKCk7IHBsb3QodHJhal8wMywgbHdkID0gMSwgbHR5ID0gMSkKYGBgCgojIyBTZXBhcmF0aW5nIGRpc3RpbmN0IHRyYWplY3RvcmllcwoKVGhlIGZvbGxvd2luZyB0cmFqZWN0b3JpZXMgZG8gbm90IGZpdCBnZW5lcmFsIHNldHRpbmdzIGFwcGxpZWQgdG8gdGhlIHJlc3Qgb2YgdGhlIHRyYWplY3RvcmllcyBhbmQgYXJlIHRodXMgdXNpbmcgcGFydGljdWxhciBzZXR0aW5ncyBzaG93biBiZWxvdyAoc2VjdGlvbiAiRGlzdGluY3QgdHJhamVjdG9yaWVzIikuCgpgYGB7cn0KCnJlbW92YWJsZXMgPC0gYygyLCAzLCAxMikKCmRlcml2c19saXN0X3Nob3J0IDwtIGRlcml2c19saXN0Wy0gcmVtb3ZhYmxlc10KZGVyaXZzX25hbWVzX3Nob3J0IDwtIGRlcml2c19uYW1lc1stIHJlbW92YWJsZXNdCiMgbmFtZXMoZGVyaXZzX2xpc3Rfc2hvcnQpIDwtIGRlcml2c19uYW1lc19zaG9ydAoKYGBgCgojIyBGcmFtZSBpbmRleGVzCgpgYGB7cn0KIyBUaGUgIkluZGV4TGltaXRzTWFudWFsIiBmdW5jdGlvbiBwdWxscyB0aGUgaW5kZXggcG9zaXRpb24gb2YgdGhlIGZvbGxvd2luZyBmcmFtZXM6CiMgbGFzdCBmcmFtZSB3aGVyZSBzcGVlZCBpcyB6ZXJvICh0aGUgb25zZXQgb2YgdGhlIGFudCBzbGF5ZXIgYXR0YWNrKQojIGZyYW1lIHdoZXJlIHRoZSBhY3JvYmF0aWMgc3RyaWtlIHJlYWNoZXMgaXRzIG1heHVtdW0gc3BlZWQKCiMgZGVmYXVsdCB2YWx1ZXMgdXNlZCBmb3IgdGhlIGZ1bmN0aW9uCiMgSW5kZXhMaW1pdHNNYW51YWwoZGVyaXZzX29iamVjdCA9IGRlcml2c19saXN0X3NhbXBsZSREZXJpdnNfMDEsIHN0YXJ0VGhyZXNob2xkID0gMWUtOCwgdGhyZXNob2xkRnJhbWUgPSAxLCBsaW1pdF9yYW5nZSA9IDE1NSwgd2luZG93X3NpemUgPSAzNSkKCmluZGV4ZXNfc2hvcnQgPC0gbWFwKGRlcml2c19saXN0X3Nob3J0LCBJbmRleExpbWl0c01hbnVhbCkKIyBuYW1lcyhpbmRleGVzX3Nob3J0KQpgYGAKCiMjIE1heGltYSBzcGVlZHMKClRoZSBmb2xsb3dpbmcgcGxvdHMgc2hvdyB0aGUgc3BlZWQgY2hhbmdlIGR1cmluZyB0aGUgZmlyc3QgcGhhc2Ugb2YgdGhlIGF0dGFjayAoYWNyb2JhdGljIHN0cmlrZSkgVGhlIGJsdWUgdmVydGljYWwgbGluZSBtYXJrcyB0aGUgb25zZXQgb2YgdGhlIHNwaWRlcnMnIGF0dGFjayAodGhlIHNwaWRlciBiZWdpbnMgbW92aW5nKSBUaGUgcmVkIGxpbmUgc2hvd3Mgd2hlcmUgdGhlIHBlYWsgc3BlZWQgd2FzIHJlYWNoZWQgZHVyaW5nIHRoZSBhY3JvYmF0aWMgc3RyaWtlIE5vdGUgdGhpcyBpcyByZXN0cmljdGVkIHRvIHRoZSBzcGVlZHMgYWNoaWV2ZWQgYnkgdGhlIHNwaWRlcnMgKip3aGlsZSoqIGRpcmVjdGluZyBpdHMgYXR0YWNrIHRvIHRoZSBhbnQgcHJleSBhbmQgKipiZWZvcmUqKiBkcm9wcGluZyBvZmYgZnJvbSB0aGUgdHJ1bmsgc3VyZmFjZS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CnBtYXAobGlzdChkZXJpdnNfbGlzdF9zaG9ydCwgYXMubGlzdChuYW1lcyhkZXJpdnNfbGlzdF9zaG9ydCkpLCBpbmRleGVzX3Nob3J0KSwgCiAgICAgfmdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PSAuLjEkc3BlZWRUaW1lcyoxMDAwLCB5PSAuLjEkc3BlZWQqMTAwKSkgKwogICAgICAgZ2d0aXRsZSguLjIpICsKICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC4uMyRgbWF4aW0odW0vYSlgKjQsIGNvbCA9ICJyZWQiKSsKICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLi4zJHN0YXJ0X2luZGV4KSo0LCBjb2wgPSAiYmx1ZSIpICsgCiAgICAgICB4bGFiKCJUaW1lIChtcykiKSArCiAgICAgICB5bGFiKCJTcGVlZCAoY20vcykiKSArCiAgICAgICB0aGVtZV9idygpCikKYGBgCgojIyBEaXN0aW5jdCB0cmFqZWN0b3JpZXMKClRyYWplY3RvcmllcyAwMiBhbmQgMTIgd2VyZSBhZmZlY3RlZCBieSBub2lzeSBzcGVlZCBjdXJ2ZXMgYmVmb3JlIHRoZSBvbnNldCBvZiB0aGUgYXR0YWNrLiBUaGVzZSB3ZXJlIGFkanVzdGVkIGFuZCBjb3Jyb2JvcmF0ZWQgd2l0aCB2aXN1YWwgaW5zcGVjdGlvbiBvZiB0aGUgdmlkZW9zIHRvIG1ha2Ugc3VyZSB0aGF0IHRoZSBzZWxlY3RlZCBmcmFtZSB3YXMgdGhlIGxhc3Qgb25lIGJlZm9yZSB0aGUgYXR0YWNrIG9uc2V0LgoKYGBge3J9CiMgcmVtb3ZhYmxlcyA8LSBjKDIsIDMsIDEyKQoKZGVyaXZzX2xpc3Rfc3BlY2lhbCA8LSBkZXJpdnNfbGlzdFtyZW1vdmFibGVzXQpkZXJpdnNfbmFtZXNfc3BlY2lhbCA8LSBkZXJpdnNfbmFtZXNbcmVtb3ZhYmxlc10KbmFtZXMoZGVyaXZzX2xpc3Rfc3BlY2lhbCkgPC0gZGVyaXZzX25hbWVzX3NwZWNpYWwKIyBzdHIoZGVyaXZzX2xpc3Rfc3BlY2lhbCkKCmBgYAoKRGVyaXZzIDAyCgpgYGB7cn0KIyBnZXQgaW5kZXggZnJhbWVzCmluZGV4ZXNfZGVyaXZzXzAyIDwtIEluZGV4TGltaXRzTWFudWFsKGRlcml2c19vYmplY3QgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18wMiwgc3RhcnRUaHJlc2hvbGQgPSAxZS04LCB0aHJlc2hvbGRGcmFtZSA9IDE5LCBsaW1pdF9yYW5nZSA9IDE1NSwgd2luZG93X3NpemUgPSAyNSkKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKHggPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18wMiRzcGVlZFRpbWVzKjEwMDAsIHkgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18wMiRzcGVlZCoxMDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gaW5kZXhlc19kZXJpdnNfMDIkYG1heGltKHVtL2EpYFsyXSo0LCBjb2wgPSAicmVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoaW5kZXhlc19kZXJpdnNfMDIkc3RhcnRfaW5kZXgsIGluZGV4ZXNfZGVyaXZzXzAyJGVuZF9pbmRleCkqNCwgY29sID0gImJsdWUiKSArIAogIGxhYnModGl0bGUgPSAiRGVyaXZzXzAyIiwgCiAgICAgICB4ID0gIlRpbWUgKG1zKSIsCiAgICAgICB5ID0gIlNwZWVkIChjbS9zKSIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgaW5kZXhlc19kZXJpdnNfMDIkYG1heGltKHVtL2EpYAojIGluZGV4ZXNfZGVyaXZzXzAyJGVuZF9pbmRleAoKYGBgCgpEZXJpdnMgMTIKCmBgYHtyfQojIGdldCBpbmRleCBmcmFtZXMKaW5kZXhlc19kZXJpdnNfMTIgPC0gSW5kZXhMaW1pdHNNYW51YWwoZGVyaXZzX29iamVjdCA9IGRlcml2c19saXN0X3NwZWNpYWwkRGVyaXZzXzEyLCBzdGFydFRocmVzaG9sZCA9IDFlLTgsIHRocmVzaG9sZEZyYW1lID0gMTksIGxpbWl0X3JhbmdlID0gMTU1LCB3aW5kb3dfc2l6ZSA9IDM1KQoKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKHggPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18xMiRzcGVlZFRpbWVzKjEwMDAsIHkgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18xMiRzcGVlZCoxMDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gaW5kZXhlc19kZXJpdnNfMTIkYG1heGltKHVtL2EpYCo0LCBjb2wgPSAicmVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoaW5kZXhlc19kZXJpdnNfMTIkc3RhcnRfaW5kZXgsIGluZGV4ZXNfZGVyaXZzXzEyJGVuZF9pbmRleCkqNCwgY29sID0gImJsdWUiKSArIAogIGxhYnModGl0bGUgPSAiRGVyaXZzXzEyIiwgCiAgICAgICB4ID0gIlRpbWUgKG1zKSIsCiAgICAgICB5ID0gIlNwZWVkIChjbS9zKSIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgaW5kZXhlc19kZXJpdnNfMDIkYG1heGltKHVtL2EpYAojIGluZGV4ZXNfZGVyaXZzXzAyJGVuZF9pbmRleAoKYGBgCgojIyBGaWd1cmUgMSBQYW5lbCBGCgpUaGUgZmlndXJlIHBsb3RzIHRoZSBzcGVlZCBjaGFuZ2UgZnJvbSB0aGUgbGFzdCBmcmFtZSBiZWZvcmUgdGhlIGFjcm9iYXRpYyBhdHRhY2sgb25zZXQgdG8gdGhlIG1heGltdW0gc3BlZWQgcmVhY2hlZCBmb3IgMTcvMTkgaW5zcGVjdGVkIGhpZ2ggc3BlZWQgdmlkZW9zLiBUaGUgcmVtYWluaW5nIDIgKDAyIGFuZCAxMikgYXJlIGFkZGVkIGxhdGVyLgoKYGBge3J9CgojIGxvb3AgbWUgdXAhCiMgY29sb3VyIHBhbGV0dGUKY2JwMSA8LSBjKCIjOTk5OTk5IiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIsICIjMDA5RTczIiwKICAgICAgICAgICIjRjBFNDQyIiwgIiMwMDcyQjIiLCAiI0Q1NUUwMCIsICIjQ0M3OUE3IikKIyB0byByZWN5Y2xlIGNvbG91cnMKY2JwMV8yNCA8LSByZXAoY2JwMSwgMykKCm1wIDwtIGdncGxvdCgpCmZvcihpIGluIHNlcV9hbG9uZyhkZXJpdnNfbGlzdF9zaG9ydCkpIHsKICAKICBpZGF0YSA8LSB0aWJibGUoInNwZWVkIiA9IGRlcml2c19saXN0X3Nob3J0W1tpXV0kc3BlZWRbaW5kZXhlc19zaG9ydFtbaV1dJHN0YXJ0X2luZGV4OmluZGV4ZXNfc2hvcnRbW2ldXSRgbWF4aW0odW0vYSlgXSkgJT4lIAogICAgbXV0YXRlKCJpbmRleCIgPSBzZXFfYWxvbmcoc3BlZWQpLTEpCiAgCiAgbXAgPC0gbXAgKyBnZW9tX2xpbmUoZGF0YSA9IGlkYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGluZGV4KjQsIHkgPSBzcGVlZCoxMDApLCBjb2xvdXIgPSBjYnAxXzI0W2ldKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSBpZGF0YSwKICAgICAgICAgICAgICAgYWVzKHggPSBsYXN0KGluZGV4KSo0LCAKICAgICAgICAgICAgICAgICAgIHkgPSAgbGFzdChzcGVlZCoxMDApKSwgCiAgICAgICAgICAgICAgIGNvbG91ciA9IGNicDFfMjRbaV0pICsKICAgIGV4cGFuZF9saW1pdHMoeCA9IGMoMCwgMTYwKSwgeSA9IGMoMCwgNjUpKSArCiAgICB5bGFiKCJTcGVlZCAoY20vcykiKSArCiAgICB4bGFiKCJUaW1lIChtcykiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKQp9CgojIHRoZSB2ZXJzaW9uIGJlbG93IGRvZXMgbm90IGluY2x1ZGUgc3BlZWQgZm9yIHRyYWplY3RvcmllcyAwMiBhbmQgMTIKIyBwcmludChtcCkKCgojIG1wICsgCiMgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIC4xKSkpICsKIyAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgLjEpKSkKCmBgYAoKQ3VydmVzIGZvciB0cmFqZWN0b3JpZXMgMDIgYW5kIDEyIGFyZSBjcmVhdGVkIHdpdGggdGhlIGRpc3RpbmN0IHNldHRpbmdzIGNyZWF0ZWQgYmVmb3JlIHRvIGNhcHR1cmUgdGhlIGNvcnJlY3QgZnJhbWVzIG9mIGltcG9ydGFuY2UKCmBgYHtyfQojIDAyCmRlcml2c18wMl9kYXRhIDwtIHRpYmJsZSgic3BlZWQiID0gZGVyaXZzX2xpc3Rfc3BlY2lhbCREZXJpdnNfMDIkc3BlZWRbaW5kZXhlc19kZXJpdnNfMDIkc3RhcnRfaW5kZXg6aW5kZXhlc19kZXJpdnNfMDIkYG1heGltKHVtL2EpYFsyXV0pICU+JSAKICBtdXRhdGUoImluZGV4IiA9IHNlcV9hbG9uZyhzcGVlZCktMSkKCm1wIDwtIG1wICArCmdlb21fbGluZShkYXRhID0gZGVyaXZzXzAyX2RhdGEsIAogICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGluZGV4KjQsIHkgPSBzcGVlZCoxMDApLCBjb2xvdXIgPSBjYnAxXzI0WzddKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGVyaXZzXzAyX2RhdGEsCiAgICAgICAgICAgICBhZXMoeCA9IGxhc3QoaW5kZXgpKjQsIAogICAgICAgICAgICAgICAgIHkgPSAgbGFzdChzcGVlZCoxMDApKSwgCiAgICAgICAgICAgICBjb2xvdXIgPSBjYnAxXzI0WzddKSArCiAgZXhwYW5kX2xpbWl0cyh4ID0gYygwLCAxNjApLCB5ID0gYygwLCA2NSkpICsKICB5bGFiKCJTcGVlZCAoY20vcykiKSArCiAgeGxhYigiVGltZSAobXMpIikgKwogIHRoZW1lX2J3KCkKCiMgMTIKZGVyaXZzXzEyX2RhdGEgPC0gdGliYmxlKCJzcGVlZCIgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18xMiRzcGVlZFtpbmRleGVzX2Rlcml2c18xMiRzdGFydF9pbmRleDppbmRleGVzX2Rlcml2c18xMiRgbWF4aW0odW0vYSlgXSkgJT4lIAogIG11dGF0ZSgiaW5kZXgiID0gc2VxX2Fsb25nKHNwZWVkKS0xKQoKbXAgPC0gbXAgICsKZ2VvbV9saW5lKGRhdGEgPSBkZXJpdnNfMTJfZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gaW5kZXgqNCwgeSA9IHNwZWVkKjEwMCksIGNvbG91ciA9IGNicDFfMjRbOF0pICsKICBnZW9tX3BvaW50KGRhdGEgPSBkZXJpdnNfMTJfZGF0YSwKICAgICAgICAgICAgIGFlcyh4ID0gbGFzdChpbmRleCkqNCwgCiAgICAgICAgICAgICAgICAgeSA9ICBsYXN0KHNwZWVkKjEwMCkpLCAKICAgICAgICAgICAgIGNvbG91ciA9IGNicDFfMjRbOF0pICsKICBleHBhbmRfbGltaXRzKHggPSBjKDAsIDE2MCksIHkgPSBjKDAsIDY1KSkgKwogIHlsYWIoIlNwZWVkIChjbS9zKSIpICsKICB4bGFiKCJUaW1lIChtcykiKSArCiAgdGhlbWVfYncoKQoKYGBgCgpQbG90IGluY2x1ZGluZyBzcGVlZCBjaGFuZ2VzIGZvciBhbGwgdHJhamVjdG9yaWVzCgpgYGB7cn0KcHJpbnQobXApCiMgbXArdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIFNwZWVkICYgZHVyYXRpb24KCk1heCBzcGVlZHMgZm9yIGVhY2ggc3BpZGVyIGFuZCB0aGUgZWxhcHNlZCB0aW1lIHdoaWxlIGdvaW5nIGZyb20gMCB0byB0byBtYXguCgpgYGB7cn0KcmVzdWx0cyA8LSBtYXBfZGZyKGRlcml2c19saXN0X3Nob3J0LCBTcGVlZEFuZFRpbWUyKQojIHJlc3VsdHMgJT4lIGtibCgpICU+JSAKIyAgIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYpCgojIHJlbmFtZSgiTWF4IHNwZWVkIChjbS9zKSIgPSBtYXhfc3BlZWQsIAojICAgICAgICAiRWxhcHNlZCB0aW1lIChtcykiID0gZWxhcHNlZF90aW1lKQpgYGAKCmBgYHtyfQpyZXNfMDIgPC0gU3BlZWRBbmRUaW1lMihkZXJpdmF0aXZlc19saXN0ID0gZGVyaXZzX2xpc3Rfc3BlY2lhbCREZXJpdnNfMDIsIHRocmVzaG9sZEZyYW1lID0gMTksIHdpbmRvd19zaXplID0gMjUsIG11bHRpTWF4ID0gMikKCnJlc18xMiA8LSBTcGVlZEFuZFRpbWUyKGRlcml2YXRpdmVzX2xpc3QgPSBkZXJpdnNfbGlzdF9zcGVjaWFsJERlcml2c18xMiwgdGhyZXNob2xkRnJhbWUgPSAxOSwgd2luZG93X3NpemUgPSAzNSkKYGBgCgpgYGB7cn0Kc3BlZWRzX3RpbWVzIDwtIGJpbmRfcm93cyhyZXN1bHRzLCByZXNfMDIsIHJlc18xMikgJT4lIAogIG11dGF0ZShjYW1lZnJvbSA9IGMoZGVyaXZzX25hbWVzX3Nob3J0LCAiRGVyaXZzXzAyIiwgIkRlcml2c18xMiIpKSAKCnNwZWVkc190aW1lcyAlPiUga2JsKCkgJT4lIAogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYpCgpzcGVlZHNfdGltZXMgJT4lIAogIHN1bW1hcmlzZShhdmdTcGVlZCA9IG1lYW4obWF4X3NwZWVkKSwgYXZnVGltZSA9IG1lYW4oZWxhcHNlZF90aW1lKSkKCiMgdGhlIG1lZGlhbgp0YWJsZShzcGVlZHNfdGltZXMkZWxhcHNlZF90aW1lKQptZWRpYW4oc3BlZWRzX3RpbWVzJGVsYXBzZWRfdGltZSkgCgppbnNldCA8LSBzcGVlZHNfdGltZXMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoZWxhcHNlZF90aW1lKSkgKwogIGV4cGFuZF9saW1pdHMoeCA9IGMoMCwgMTYwKSkgKwogIHRoZW1lKCBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICMgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50Iixjb2xvdXIgPSBOQSksCiAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50Iixjb2xvdXIgPSBOQSksCikKICAKaW5zZXQgPC0gaW5zZXQgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgICAgICAjIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgKQoKYGBgCgpQYW5lbCBGIGluIGZpZ3VyZSAxIGluY2x1ZGluZyBpbnNldCBib3ggcGxvdCBmb3IgZWxhcHNlZCB0aW1lIGR1cmluZyBzcGVlZCBjaGFuZ2UKCmBgYHtyfQoKIyBtcCtnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxMDQpK2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDE1MikgKwojIGluc2V0X2VsZW1lbnQgKHAgPSBpbnNldCwKIyBsZWZ0ID0gLTAuMDE4LAojIGJvdHRvbSA9IDAuODAsCiMgcmlnaHQgPSAxLjAxMiwKIyB0b3AgPSAwLjk1LCBhbGlnbl90byA9ICJwYW5lbCIpCgpnZ3BfY29tYmkgPC0gbXAgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBpbnNldF9lbGVtZW50IChwID0gaW5zZXQsCiAgICAgICAgICAgICAgICAgbGVmdCA9IC0wLjAxOCwKICAgICAgICAgICAgICAgICBib3R0b20gPSAwLjg5LAogICAgICAgICAgICAgICAgIHJpZ2h0ID0gMS4wMTIsCiAgICAgICAgICAgICAgICAgdG9wID0gMC45OSwgYWxpZ25fdG8gPSAicGFuZWwiKQpnZ3BfY29tYmkKCiMgZ2dzYXZlKGZpbGVuYW1lID0gInBhbmVsRi5wZGYiLCBwbG90ID0gZ2dwX2NvbWJpLCBkZXZpY2UgPSAicGRmIiwgcGF0aCA9ICIuL2dnX3Bsb3RzIikKYGBgCgpgYGB7cn0KIyBzZXR3ZCgiL1VzZXJzL2FsZm9uc29hY2V2ZXMvRG93bmxvYWRzL0FudCBTbGF5ZXIgU3BlZWQvZ2dfcGxvdHMiKQojIHdyaXRlX2NzdihzcGVlZHNfdGltZXMsICJzcGVlZHNfdGltZXMuY3N2IikKYGBgCgpgYGB7cn0KIyB0aXRsZTogIlIgTm90ZWJvb2siCiMgb3V0cHV0OgojICAgaHRtbF9kb2N1bWVudDoKIyAgICAgY29kZV9mb2xkaW5nOiAic2hvdyIKIyAgICAgdG9jOiBUUlVFCiMgICAgIHRvY19mbG9hdDogVFJVRQojICAgICBkZl9wcmludDogcGFnZWQKIyBlZGl0b3Jfb3B0aW9uczoKIyAgIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCgpgYGAKCgo8YnI+CgoKOjo6IHsudG9jaWZ5LWV4dGVuZC1wYWdlIGRhdGEtdW5pcXVlPSJ0b2NpZnktZXh0ZW5kLXBhZ2UiIHN0eWxlPSJoZWlnaHQ6IDA7In0KOjo6Cg==